
#[cfg(test)]
mod test {

    use std::thread ;
    fn f() {
        println!("Hello from another thread");

        let id = thread::current().id();
        println!("This is my thread id: {id:?}");
    }
    #[test]
    fn thread_hello(){
        let t1 = thread::spawn(f);
        let t2 = thread::spawn(f);

        println!("Hello, world from main thread");

        t1.join().unwrap();
        t2.join().unwrap();
    }

    #[test]
    fn primitive_in_thread() {
        //Compile Error 
        /*
        let x: i32 = 1_32;
        thread::spawn(||{  // <-  x may be freed if x is shared between two thread
            println!("{x}");
        }).join().unwrap();
        */
    }


    #[test]
    fn iter_in_thread() {
        let numbers = vec![1, 2, 3];

        thread::spawn( move || {
            for n in &numbers {
                println!("{n}");
            }

            for n in &numbers {
                println!("{n}");
            }
            
        }).join().unwrap();
    }
    
    #[test]
    fn average_in_thread() {
        let numbers = Vec::from_iter(0..=100);
        let average = thread::spawn(move ||{
            let len = numbers.len();
            let sum = numbers.iter().sum::<usize>();
            sum / len
        }).join().unwrap();

        println!("avarage: {average}");
    }


    #[test]
    fn scoped_threads(){
        let numbers = vec![1, 2, 3];
    
        thread::scope(|s| {
            //two threads
            s.spawn(|| { 
                println!("length : {}", numbers.len()); //borrow local var, not move
            });

            s.spawn(|| {
                for n in numbers.iter() { //borrow local var, not move
                    println!("{n}");
                }
            });
        });

    }
    #[test]
    fn primitive_in_scoped_thread() {
        let x: i32 = 1_32;
        thread::scope(|s| {
            s.spawn(||{
                println!("{x}"); // x is send, and sync
            });
        });
    }

    //Shared Ownership and Reference Counting
    #[test]
    fn shared_ownership() {
        static X: [i32; 3] = [1, 2, 3];
        thread::spawn(|| dbg!(&X));
        thread::spawn(|| dbg!(&X));

        let x: &'static [i32; 3] = Box::leak(Box::new([1, 2, 3]));
        //local ptr (Box) , but the content is static global, 
        //so move the ptr(Box)
        thread::spawn(move || dbg!(x)); //move --> copy ptr
        thread::spawn(move || dbg!(x)); //move --> copy ptr
    }

    use std::sync::Arc;
    #[test]
    fn reference_counting() {
        {
            let a = Arc::new([1, 2, 3]);
            let b = a.clone();

            thread::spawn(move || dbg!(a));
            thread::spawn(move || dbg!(b));
        }
        {
            let a = Arc::new([1, 2, 3]);
            thread::spawn({ 
                let a = a.clone(); //same name as out var
                move || dbg!(a)
            });

            dbg!(a);
        }
    }

     
    #[test]
    fn cell_refcell_single_thread_only(){
        use std::cell::Cell;
        fn cell(a: &Cell<i32>, b: &Cell<i32>){
            let before = a.get(); 
            b.set(b.get() + 1);
            let after = a.get();
            if before != after {
                //might happen, a ,b point to same value
            }

        }
        cell(&Cell::<i32>::new(1), &Cell::<i32>::new(2));

        fn cell_1(v: &Cell<Vec<i32>>){
            let mut v2 = v.take(); // replace the cell internal with an empty vec
            v2.push(1);
            v.set(v2);
        }
        cell_1(&Cell::new(Vec::<i32>::new()));

        use std::cell::RefCell;
        fn refcell(v: &RefCell<Vec<i32>>) {
            v.borrow_mut().push(1);
        }
        refcell(&RefCell::new(Vec::<i32>::new()));
    }

    #[test]
    /*
     * Send  > it can be sent to another thread
     * > ownership can be transferred to another thread; 
     * >e.g impl Send for Arc<T>;  Rc<i32> impl !Send for Rc<T>
     *
     * Sync  > it can be shared with another thread.
     * >  a shared reference to that type , &T, is Send.
     * > i32 is Sync,  Cell<i32> is not;(Cell<i32> is Send)  
     * > impl Send for &i32;  impl !Send for &Cell<T> ; 
     * > impl Send for Cell<T>
     * > primitive types , and str are both Send & Sync
     * > e.g. 1. Raw Pointers are nether Send nor Sync
     * > e.g. 2.
     */
    fn send_sync() {
        struct X {
            p: *const i32,
        }
        impl X {
            fn new() -> Self {
                Self {
                    p: std::ptr::null(),
                }
            }
            fn is_null(&self) -> bool {
                self.p.is_null()
            }
        }

        unsafe impl Send for X {}
        //unsafe impl Sync for X {} //don't know how to use it 

        let x = X::new();
        thread::spawn(move || {
            (&x).is_null()
            //x.p.is_null() => compile error, because *const i32 is not send
        });

        //TODO: use the sync of X
    }

    use std::sync::Mutex; // Sync , &T can be send to thread 
    use std::time::Duration;
    // MutexGuard of mutex provide (&T) for value
    #[test]
    fn mutex() {
        let n = Mutex::new(0);
        thread::scope( |s|{
            for _ in 0..10 {
                s.spawn( ||{ //no move
                    let mut guard = n.lock().unwrap();  //n can be shared 
                    for _ in 0..100 {
                        *guard += 1;
                    }
                    drop(guard); 
                    thread::sleep(Duration::from_millis(50)); //sleep one second
                });
            }
        });
        assert_eq!(n.into_inner().unwrap(), 1000);
    }
    
    #[test]
    fn mutex_with_no_scope() {
        let n = Arc::new(Mutex::new(0));

        for _ in 0..10 {
            //let n = Arc::clone(&n); //use this method
            thread::spawn({
                let n = Arc::clone(&n);
                move || {
                    let mut guard = n.lock().unwrap(); // tmp n is moved afte clone from Atomics ref counting facade
                    for _ in 0..100 {
                        *guard += 1;
                    }
                    drop(guard);
                    thread::sleep(Duration::from_millis(50));
                }
            });
        }
    }
    #[test]
    fn lifetime_of_mutex_gurad() {
        let list = Mutex::new(Vec::<i32>::new());
        list.lock().unwrap().push(1); //  lock and push ,and free the guard at end of this statement
        list.lock().unwrap().push(2); //  lock and push ,and free the guard at end of this statement
        list.lock().unwrap().push(3); //  lock and push ,and free the guard at end of this statement


        // if let cond.. ;  condition will borrow something to do next
        if let Some(item) = list.lock().unwrap().pop() {
            println!("{item}"); // locked the list to print item
        };// guard will free in this point , note the ";" here


        // replace last statement ==> 
        let item = list.lock().unwrap().pop();  //MutexGuard freed here
        if let Some(item) = item {  //execution in unlocked state begine
            println!("{item}"); 
        }

        // if condition statement =>   condition = bool statement, cannot borrow anything
        if list.lock().unwrap().pop() == Some(1) { //MutexGuard free here
            println!("1"); //print the item after unlocked the list 
        }

    }

    #[test] 
    fn rwlock(){
        //TODO:
    }

    #[test]
    fn parking() {
        //TODO:
    }

    /*
    #[test]
    fn atomics() {
    }*/
}
